#include "prosteFFT.h"
#include <iostream>
#include <cstring>
#include <omp.h>

using namespace std;

prosteFFT::prosteFFT(){

}

prosteFFT::prosteFFT(zespolona *dane, int size)
{
    x = new zespolona[size];
    memcpy(x, dane, size*sizeof(zespolona));
    N = size;
}

zespolona* prosteFFT::FFT_p(zespolona* x, int N){

    zespolona* X = new zespolona[N];
    zespolona *d, *e, *D, *E;

    if (N==1) {
        X[0] = x [0];

        return X;
    }

//    omp_set_num_threads(1);

    e = new zespolona[N];
    d = new zespolona[N];

    //rozbicie na 2 mniejsze

    #pragma omp parallel for num_threadss(3)
    for (int k=0; k<N/2; k++) {
        e[k] = x[2*k];
        d[k] = x[2*k + 1];
    }

    E = prosteFFT::FFT_p(e, N/2);
    D = prosteFFT::FFT_p(d, N/2);

    delete e;
    delete d;

    for (int k=0; k<N/2; k++){
        D[k] = zespolona::z_biegunowych(1, -2.0*M_PI*k/N)*D[k];
    }

    for (int k=0; k<N/2; k++){
        X[k] = E[k]+D[k];
        X[k + N/2] = E[k]-D[k];
    }

    delete [] D;
    delete [] E;



    return X;

}

zespolona* prosteFFT::threaded_FFT()
{
    zespolona** dane = sort();
}

zespolona** prosteFFT::sort()
{
    int length = N;
    int height = 1;

    zespolona ** tab = new zespolona*[height];
    tab[0] = new zespolona[length];

    for (int i = 0; i < length; ++i) {
	tab[0][i] = x[i];
    }

    int oper = 0;



    zespolona ** new_tab;
    do {
	int length_new = length / 2;
	int height_new  = 2 * height;

	new_tab = new zespolona*[height_new];
	for (int i = 0; i < height_new; ++i) {
	    new_tab[i] = new zespolona[length_new];
	}

	for (int i = 0; i < height; i++) {
	    for (int j = 0; j < length; j++) {
		int new_i = 2*i + j % 2;
		int new_j = j/2;
		zespolona tab_i_j_val = tab[i][j];
		new_tab[new_i][new_j] = tab_i_j_val;
		oper++;
	    }
	}

//	for (int i = 0; i < height_new; ++i) {
//	    for (int j = 0; j < length_new; ++j) {
//		cout << new_tab[i][j] << " ";
//	    }
//	    cout << endl;
//	}

	delete [] tab;

	tab = new_tab;

	length = length_new;
	height = height_new;


//
    } while (length != 2);
    zespolona ** wyn_tab;
    wyn_tab = new zespolona*[1];
    wyn_tab[0] = new zespolona[length];

     zespolona ** tmp_tab;
    do {
	int length_new = length * 2;
	int height_new  = height / 2;

	tmp_tab = new zespolona*[height_new];
	for (int i = 0; i < height_new; ++i) {
	    tmp_tab[i] = new zespolona[length_new];
	}

	for (int i = 0; i < height; ++i) {
	    for (int j = 0; j < length; ++j) {
		if (j%2) {
		    tab[i][j] = tab[i][j] * zespolona::z_biegunowych(1, -2.0*M_PI*j/height);
		}

		wyn_tab[i][j] = tab[i/2][j*2] + tab[i/2 + 1][2*j];
		wyn_tab[i+height_new/2][j] = tab[i/2][j*2] - tab[i/2 + 1][2*j];
//				cout << tab[i][j].re << " " << tab[i][j].im << endl;
//		cout << wyn_tab[i].re << " " << wyn_tab[i].im << endl;
//		X[k] = E[k]+D[k];
//		X[k + N/2] = E[k]-D[k];
	    }
	    cout << endl;
	}

	height = height_new;
	length = length_new;
    } while (height != 0);

    for (int i = 0; i < length; ++i) {
	cout << tab[0][i].do_biegunowych() << endl;
    }

    cout << oper << endl;

    return tab;
//    return 0;
}
